﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Web;
using System.IO;
using System.Text.RegularExpressions;
using System.Reflection;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using AliCMS.SystemModule;
using System.Security.Cryptography;
using System.Xml;

namespace AliCMS.TemplateEngine
{
    internal class Engine
    {
        internal Engine(string targetLang, bool debug, bool vedit, string veCachePrefix, string veFolder, Dictionary<string, string> dynamicTemplate)
        {
            _targetLang = targetLang;
            _debug = debug;
            _vedit = vedit;
            _veCachePrefix = veCachePrefix;
            _veFolder = veFolder;
            _isAdmin = false;
            _tags = new List<Tag>();
            _usedVars = new Dictionary<string, string>();
            _usedChannel = new List<string>();
            _usedFunctions = new List<string>();
            _tagCode = new StringBuilder();
            _assemblies = new List<string>();
            _dynamicTemplate = dynamicTemplate;
        }

        internal void CompileFile(string templatePath, string pathInTemplate)
        {
            _pathInTemplate = pathInTemplate.Replace('\\', '/');
            if (_templatePath != templatePath)
            {
                using (AliCMS.SystemModule.ITemplate bll = (AliCMS.SystemModule.ITemplate)Manager.CreateObject("Template", 0, null, false))
                {
                    _template = bll.Get(templatePath);

                    if (!Convert.ToBoolean(_template[Alias.Template.IsWebsite]))
                    {
                        if (String.IsNullOrEmpty(_template[Alias.Template.Language].ToString()))
                            _lang = "CHS";
                        else
                            _lang = _template[Alias.Template.Language].ToString();
                    }

                    _isAdmin = Convert.ToBoolean(_template[Alias.Template.IsAdmin]);

                    #region 可视编辑状态，获取可视编辑模板
                    if (_vedit)
                    {
                        foreach (DataRow row in Manager.Channels.Rows)
                        {
                            if (row[Alias.Channel.TemplatePath].ToString() == "")
                                continue;

                            Dictionary<string, object> template = bll.Get(row[Alias.Channel.TemplatePath].ToString());
                            if (template == null)
                                continue;

                            if (Convert.ToBoolean(template[Alias.Template.IsVisualEdit]))
                            {
                                _veTemplatePath = Manager.GetTemplatePath(row[Alias.Channel.TemplatePath].ToString());
                                _veChannelPath = row[Alias.Channel.Path].ToString();
                                break;
                            }
                        }
                    }
                    #endregion
                }

                _templatePath = templatePath;
                _templateModuleTable = null;
                _words = null;
            }
            string cachedTemplatePath = Manager.GetCachedTemplatePath(_veCachePrefix + templatePath, null, _debug);
            int dot = _pathInTemplate.LastIndexOf(".dwt");
            if (dot == -1)
                return;

            string csFile = cachedTemplatePath + _pathInTemplate.Substring(0, dot) + ".cs";
            string fullClassName = Manager.MakeClassName(_pathInTemplate.Substring(0, dot).Replace('.', '_'));
            dot = fullClassName.LastIndexOf('.');
            if (dot != -1)
            {
                _templateName = templatePath.TrimEnd('/').Replace('/', '_') + "." + fullClassName.Substring(0, dot);
                _className = "C" + fullClassName.Substring(dot + 1);
            }
            else
            {
                _templateName = templatePath.TrimEnd('/').Replace('/', '_');
                _className = "C" + fullClassName;
            }

            if (System.IO.Path.GetExtension(_pathInTemplate) == ".ascx")
            {
                _isControl = true;
                _baseClass = "UserControl";
            }
            else
            {
                _isControl = false;
                if (IsMultiSite)
                    _baseClass = "AliCMS.SiteModule.Page";
                else
                    _baseClass = "AliCMS.Page";
            }

            _runAt = null;
            _module = null;
            _tags.Clear();
            _usedVars.Clear();
            _usedChannel.Clear();
            _usedFunctions.Clear();
            _assemblies.Clear();
            _assemblies.Add("System");
            _assemblies.Add("System.Data");
            _assemblies.Add("System.Xml");
            _assemblies.Add("System.Collections.Generic");
            _assemblies.Add("System.Collections");
            _assemblies.Add("System.Text");
            _assemblies.Add("System.Web");
            _assemblies.Add("AliCMS");

            #region 读入模板
            if (_page == null)
                _page = (AliCMS.SystemModule.Template.IPage)Manager.CreateObject("Template.Page", 0, null, false);


            Dictionary<string, object> page = null;
            if (_pathInTemplate.StartsWith("/"))
            {
                page = _page.Get("/", _pathInTemplate.Substring(1));
            }
            else
            {
                _veSource = templatePath + _pathInTemplate;
                _veTarget = _veFolder + templatePath + _lang + "/" + _pathInTemplate;
            }

            if (page == null)
            {
                if (!String.IsNullOrEmpty(_veFolder) && File.Exists(Manager.MapPath(_veTarget)))
                {
                    page = _page.Get(_veFolder + templatePath + _lang + "/", _pathInTemplate);
                }
                else
                {
                    page = _page.Get(templatePath, _pathInTemplate);
                }
            }
            _text = page[Alias.Template.Page.Content].ToString();
            #endregion

            #region _moduleTable
            if (_moduleTable == null)
            {
                using (IModule bll = (IModule)Manager.CreateObject("Module", 0, _lang, false))
                {
                    _moduleTable = bll.List(-1, -1, (Dictionary<string, object>)null, (Dictionary<string, string>)null);
                }
            }
            #endregion

            #region _templateModuleTable
            if (_templateModuleTable == null)
            {
                using (SystemModule.Template.IModule bll = (SystemModule.Template.IModule)Manager.CreateObject("Template.Module", 0, null, false))
                {
                    Dictionary<string, object> condition = new Dictionary<string, object>();
                    condition[Alias.Template.Module.TemplatePath] = _templatePath;
                    _templateModuleTable = bll.List(-1, -1, condition, null);
                }
            }
            #endregion

            #region _mainModule, _module
            GetModuleByMark(String.Empty);
            #endregion

            ParseFile();
            WriteCSFile(Manager.MapPath(csFile));
            WriteAspxFile(csFile);

            #region 检查并编译用户控件
            if (!_isControl)
            {
                #region 控件不考虑可视编辑
                _veCachePrefix = null;
                #endregion

                string dirInTemplate = null;
                #region 考虑管理模板，并且命名空间下
                if (_isAdmin && _pathInTemplate.StartsWith("/"))
                {
                    int pageIndex = _pathInTemplate.IndexOf("/page/");
                    dirInTemplate = System.IO.Path.GetDirectoryName(_pathInTemplate.Substring(pageIndex + 1));
                }
                #endregion
                else
                {
                    dirInTemplate = System.IO.Path.GetDirectoryName(_pathInTemplate);
                }

                MatchCollection matches = Regex.Matches(_text, @"<%@ Register.*Src=""(?<v>.*?)"".*%>", RegexOptions.Compiled);
                foreach (Match match in matches)
                {
                    string value = match.Groups["v"].Value;
                    string ascxTemplatePath = templatePath;
                    string templateFullPath = Manager.MapPath(Manager.GetTemplatePath(ascxTemplatePath));
                    string ascxFullPath = System.IO.Path.GetFullPath(System.IO.Path.Combine(templateFullPath + dirInTemplate, value));
                    if (!File.Exists(ascxFullPath))
                        continue;

                    #region 考虑用户控件在网站模板下
                    int def = Regex.Matches(value, "../").Count - Regex.Matches(_pathInTemplate, "/").Count;
                    ascxTemplatePath = ascxTemplatePath.TrimEnd('/');
                    while (def > 0 && ascxTemplatePath.IndexOf("/") != -1)
                    {
                        ascxTemplatePath = System.IO.Path.GetDirectoryName(ascxTemplatePath).Replace('\\', '/');
                        value = value.Remove(0, 3);
                        def--;
                    }
                    #endregion

                    string cachedTemplateFullPath = Manager.MapPath(Manager.GetCachedTemplatePath(ascxTemplatePath, _targetLang, _debug));
                    string cachedAscxFullPathWithDwt = System.IO.Path.GetFullPath(System.IO.Path.Combine(cachedTemplateFullPath + dirInTemplate, value));
                    dot = cachedAscxFullPathWithDwt.LastIndexOf(".dwt");
                    if (dot == -1)
                        continue;
                    string cachedAscxFullPath = cachedAscxFullPathWithDwt.Substring(0, dot) + System.IO.Path.GetExtension(cachedAscxFullPathWithDwt);
                    if (!File.Exists(cachedAscxFullPath) || (File.GetLastWriteTime(ascxFullPath) != File.GetLastWriteTime(cachedAscxFullPath)))
                    {
                        string ascxPathInTemplate = cachedAscxFullPathWithDwt.Substring(cachedTemplateFullPath.Length);
                        CompileFile(ascxTemplatePath + "/", ascxPathInTemplate);
                        File.SetLastWriteTime(cachedAscxFullPath, File.GetLastWriteTime(ascxFullPath));
                    }
                }
            }
            #endregion
        }
        internal void Translate(string templatePath, string pathInTemplate)
        {
            if (_templatePath != templatePath)
            {
                using (AliCMS.SystemModule.ITemplate bll = (AliCMS.SystemModule.ITemplate)Manager.CreateObject("Template", 0, null, false))
                {
                    _template = bll.Get(templatePath);

                    if (!Convert.ToBoolean(_template[Alias.Template.IsWebsite]))
                    {
                        if (String.IsNullOrEmpty(_template[Alias.Template.Language].ToString()))
                            _lang = "CHS";
                        else
                            _lang = _template[Alias.Template.Language].ToString();
                    }

                    _isAdmin = Convert.ToBoolean(_template[Alias.Template.IsAdmin]);
                }

                _templatePath = templatePath;
                _words = null;
            }

            string sourceRoot = Manager.MapPath(Manager.GetCachedTemplatePath(templatePath, _lang, _debug));
            string targetRoot = Manager.MapPath(Manager.GetCachedTemplatePath(templatePath, _targetLang, _debug));

            #region 如果当前页面的源文件不存在，先进行编译
            if (!File.Exists(sourceRoot + pathInTemplate.Replace(".dwt", "")))
            {
                string temp = _targetLang;
                _targetLang = _lang;
                CompileFile(templatePath, pathInTemplate);
                _targetLang = temp;
            }
            #endregion

            string[] files = Directory.GetFiles(sourceRoot, "*.as?x", SearchOption.AllDirectories);
            foreach (string sourcefile in files)
            {
                string relative = sourcefile.Substring(sourceRoot.Length);
                string targetFile = targetRoot + relative;
                Manager.MakeSureFolderExist(System.IO.Path.GetDirectoryName(targetFile));

                StreamReader sr = new StreamReader(sourcefile, Encoding.UTF8);
                StringBuilder page = new StringBuilder(sr.ReadToEnd());
                sr.Close();
                sr = null;

                #region 翻译内容
                TranslateContent(page, _lang, _targetLang);
                #endregion

                #region 处理{标识}
                MatchCollection matches = Regex.Matches(page.ToString(), @"\{(?<v>[a-zA-Z0-9_]+)\}");
                foreach (Match match in matches)
                {
                    string name = match.Groups["v"].Value;
                    foreach (DataRow word in Words)
                    {
                        if (word[Alias.Template.Dictionary.Name].ToString() == name)
                        {
                            page.Remove(match.Index, match.Length);
                            page.Insert(match.Index, word[Alias.Template.Dictionary.To]);
                            break;
                        }
                    }
                }
                #endregion

                StreamWriter sw = new StreamWriter(targetFile, false, Encoding.UTF8);
                sw.Write(page.ToString());
                sw.Close();
                sw = null;
            }
        }

        internal string ParseExpression(Tag tag, string value)
        {
            Expression expression = new Expression(tag, value);
            return expression.Parse();
        }

        internal string ParseVariable(Expression variable)
        {
            string value = variable.Value;
            if (_usedVars.ContainsKey(value))
                return _usedVars[value];

            #region Site
            Match match = Regex.Match(value, @"(?<=(^|[^\w\.]))Site\[(?<v>\w+)\]");
            if (match.Success)
            {
                string key = null;
                DataRow objectRow = Manager.Objects.Select(Alias.Module.Object.Namespace + "='AliCMS.SystemModule' and " + Alias.Module.Object.Name + "='InstanceConfig'")[0];
                DataRow[] properties = Manager.Properties.Select(Alias.Module.Object.Property.ObjectID + "='" + objectRow[Alias.Module.Object.ID] + "' and " + Alias.Module.Object.Property.Name + "='" + match.Groups["v"].Value + "'");
                if (properties.Length == 1)
                {
                    if (Convert.ToBoolean(properties[0][Alias.Module.Object.Property.MultiLanguage]))
                        key = "AliCMS.SystemModule.Alias.InstanceConfig." + match.Groups["v"].Value + " + PageLang";
                    else
                        key = "AliCMS.SystemModule.Alias.InstanceConfig." + match.Groups["v"].Value;

                    _usedVars.Add(value, value.Remove(match.Index, match.Length).Insert(match.Index, "Manager.Site[" + key + "]"));
                    return _usedVars[value];
                }
            }
            #endregion

            #region Channel
            match = Regex.Match(value, @"(?<=(^|[^\w\.]))Channel\[(?<v>\w+)\]");
            if (match.Success)
            {
                string key = String.Empty;
                string v = match.Groups["v"].Value;
                switch (v)
                {
                    case "ModuleID":
                    case "ModuleName":
                    case "ModuleNamespace":
                    //case "ModuleIsSystem":
                    //case "ModuleIsMember":
                        key = "AliCMS.SystemModule.Alias.Module." + v.Substring("Module".Length);
                        break;
                    case "InstanceName":
                        key = "AliCMS.SystemModule.Alias.Instance.Name + PageLang";
                        break;
                    case "InstanceID":
                    case "InstanceInnerID":
                        key = "AliCMS.SystemModule.Alias.Instance." + v.Substring("Instance".Length);
                        break;
                    default:
                        {
                            DataRow objectRow = Manager.Objects.Select(Alias.Module.Object.Namespace + "='AliCMS.SystemModule' and " + Alias.Module.Object.Name + "='Channel'")[0];
                            DataRow[] properties = Manager.Properties.Select(Alias.Module.Object.Property.ObjectID + "='" + objectRow[Alias.Module.Object.ID] + "' and " + Alias.Module.Object.Property.Name + "='" + match.Groups["v"].Value + "'");
                            if (properties.Length == 1)
                            {
                                if (Convert.ToBoolean(properties[0][Alias.Module.Object.Property.MultiLanguage]))
                                    key = "AliCMS.SystemModule.Alias.Channel." + match.Groups["v"].Value + " + PageLang";
                                else
                                    key = "AliCMS.SystemModule.Alias.Channel." + match.Groups["v"].Value;
                            }
                        }
                        break;
                }

                if (key != String.Empty)
                {
                    _usedVars.Add(value, value.Remove(match.Index, match.Length).Insert(match.Index, "Channel[" + key + "]"));
                    return _usedVars[value];
                }
            }
            #endregion

            #region SubSite
            if (IsMultiSite)
            {
                match = Regex.Match(value, @"(?<=(^|[^\w\.]))SubSite\[(?<v>\w+)\]");
                if (match.Success)
                {
                    string key = String.Empty;

                    DataRow objectRow = Manager.Objects.Select(Alias.Module.Object.Namespace + "='AliCMS.SiteModule' and " + Alias.Module.Object.Name + "='Site'")[0];
                    DataRow[] properties = Manager.Properties.Select(Alias.Module.Object.Property.ObjectID + "='" + objectRow[Alias.Module.Object.ID] + "' and " + Alias.Module.Object.Property.Name + "='" + match.Groups["v"].Value + "'");
                    if (properties.Length == 1)
                    {
                        key = "AliCMS.SiteModule.Alias.Site." + match.Groups["v"].Value;
                    }

                    if (key != String.Empty)
                    {
                        _usedVars.Add(value, value.Remove(match.Index, match.Length).Insert(match.Index, "SubSite[" + key + "]"));
                        return _usedVars[value];
                    }
                }
            }
            #endregion

            #region SubChannel
            if (IsMultiSite)
            {
                match = Regex.Match(value, @"(?<=(^|[^\w\.]))SubChannel\[(?<v>\w+)\]");
                if (match.Success)
                {
                    string key = String.Empty;

                    DataRow objectRow = Manager.Objects.Select(Alias.Module.Object.Namespace + "='AliCMS.SiteModule' and " + Alias.Module.Object.Name + "='Channel'")[0];
                    DataRow[] properties = Manager.Properties.Select(Alias.Module.Object.Property.ObjectID + "='" + objectRow[Alias.Module.Object.ID] + "' and " + Alias.Module.Object.Property.Name + "='" + match.Groups["v"].Value + "'");
                    if (properties.Length == 1)
                    {
                        key = "AliCMS.SiteModule.Alias.Channel." + match.Groups["v"].Value;
                    }

                    if (key != String.Empty)
                    {
                        _usedVars.Add(value, value.Remove(match.Index, match.Length).Insert(match.Index, "SubChannel[" + key + "]"));
                        return _usedVars[value];
                    }
                }
            }
            #endregion

            #region User
            match = Regex.Match(value, @"(?<=(^|[^\w\.]))(?<v>User)\[""\w+""\]");
            if (match.Success && GetTagById(null, "User") == null)
            {
                _usedVars.Add(value, value.Remove(match.Groups["v"].Index, match.Groups["v"].Length).Insert(match.Groups["v"].Index, "Manager.User"));
                return _usedVars[value];
            }
            #endregion

            #region 全局变量
            switch (value)
            {
                case "Footer":
                case "Notice":
                case "StatCode":
                case "Logo":
                case "Link":
                case "MetaKeywords":
                case "MetaDescription":
                    _usedVars.Add(value, value);
                    break;
            }
            #endregion

            #region 站群全局变量
            switch (value)
            {
                case "SubWebPath":
                    _usedVars.Add(value, value);
                    break;
            }
            #endregion

            #region 用户栏目变量
            if (value == "UserChannel")
            {
                if (!_usedChannel.Contains("User"))
                    _usedChannel.Add("User");
            }
            #endregion

            return null;
        }
        internal string ParseFunction(Expression function)
        {
            if (function.FunctionName == "BuildUrl")
            {
                if (function.Params.Count == 1)//BuildUrl(pathInTemplate)
                {
                    function.InsertParam(0, "Channel", true);
                    function.InsertParam(-1, "null", true);
                }
                else if (function.Params.Count == 2)
                {
                    if (((function.Params[0].StartsWith("'") && function.Params[0].EndsWith("'")) || (function.Params[0].StartsWith("\"") && function.Params[0].EndsWith("\""))) &&
                        ((function.Params[1].StartsWith("'") && function.Params[1].EndsWith("'")) || (function.Params[1].StartsWith("\"") && function.Params[1].EndsWith("\"")))
                        )//BuildUrl(Mark, pathInTemplate)
                    {
                        function.Params[0] = ParseChannel(function.Params[0].Trim(new char[] { '\'', '"' }));
                        //function.Params[1] = function.Params[1].Trim(new char[] { '\'', '"' });
                        function.InsertParam(-1, "null", true);
                    }
                    else//BuildUrl(pathInTemplate,id) or BuildUrl(pathInTemplate,header)
                    {
                        function.InsertParam(0, "Channel", true);

                        if (function.Params[2].StartsWith("(") && function.Params[2].EndsWith(")"))
                            function.Params[2] = function.Params[2].Substring(1, function.Params[2].Length - 2);

                        if (!function.Params[2].StartsWith("\""))
                        {
                            Tag tag = GetTagById(null, function.Params[2]);
                            if (tag is Get)//Get标签的ID
                            {
                                function.Params.RemoveAt(2);
                                function.Params.RemoveAt(0);
                                string result = (tag as Get).ParseFunction(function);
                                if (result == null)
                                    function.Params[2] = "\"ID=\" + " + function.Params[2];
                            }
                            else
                            {
                                function.Params[2] = "\"ID=\" + " + function.Params[2];
                            }
                        }
                    }
                }
                else if (function.Params.Count == 3)//BuildUrl(Mark,pathInTemplate,id) or BuildUrl(Mark,pathInTemplate,header)
                {
                    if (((function.Params[0].StartsWith("'") && function.Params[0].EndsWith("'")) || (function.Params[0].StartsWith("\"") && function.Params[0].EndsWith("\""))))
                        function.Params[0] = ParseChannel(function.Params[0].Trim(new char[] { '\'', '"' }));

                    if (function.Params[2].StartsWith("(") && function.Params[2].EndsWith(")"))
                        function.Params[2] = function.Params[2].Substring(1, function.Params[2].Length - 2);

                    if (!function.Params[2].StartsWith("\""))
                        function.Params[2] = "\"ID=\" + " + function.Params[2];
                }
            }
            else if (function.FunctionName == "HasRight")
            {
                if (function.Params.Count == 4)
                {
                    function.InsertParam(0, "null", true);
                    function.InsertParam(-1, "Guid.Empty", true);
                }
                else if (function.Params.Count == 5)
                {
                    function.InsertParam(-1, "Guid.Empty", true);
                }
            }
            else if (function.FunctionName == "JsPath" || function.FunctionName == "CssPath")
            {
                if (!_usedFunctions.Contains(function.FunctionName))
                    _usedFunctions.Add(function.FunctionName);
                function.FunctionName = "Get" + function.FunctionName;
            }

            return function.FunctionName;
        }
        internal string ParseChannel(string mark)
        {
            if (!_usedChannel.Contains(mark))
                _usedChannel.Add(mark);

            if (String.IsNullOrEmpty(mark))
                return IsMultiSite ? "SubChannel" : "Channel";
            else
                return mark + "Channel";
        }

        internal Tag GetTagById(Tag tag, string id)
        {
            List<Tag> tags = null;
            if (tag == null)
                tags = _tags;
            else
                tags = tag.ChildTags;

            foreach (Tag t in tags)
            {
                if (t.Id == id)
                    return t;

                tag = GetTagById(t, id);
                if (tag != null)
                    return tag;
            }

            return null;
        }
        internal DataRow GetModuleByMark(string mark)
        {
            if (mark == null && _mainModule != null)
                return _mainModule;

            if (String.IsNullOrEmpty(mark) && _module != null)
                return _module;

            DataRow[] rows = _templateModuleTable.Select(Alias.Template.Module.Mark + "='" + mark + "'");
            if (rows.Length == 0)
            {
                rows = _moduleTable.Select(Alias.Module.Name + "='" + mark + "'");
                if (rows.Length > 0)
                    return rows[0];

                /*
                #region 当Mark为Guid时，表示Instance的ID。主要用在“应用”上。通过可视编辑的方式选择自己的应用，对应的实例ID放在Mark里。
                if (Regex.IsMatch(instance, @"\{?[a-fA-F0-9]{8}(-?[a-fA-F0-9]{4}){3}-?[a-fA-F0-9]{12}\}?"))
                {
                    rows = Manager.Instances.Select(Alias.Instance.ID + "='" + (new Guid(mark)) + "'");
                    if (rows.Length > 0)
                    {
                        rows = _moduleTable.Select(Alias.Module.ID + "='" + rows[0][Alias.Instance.ModuleID] + "'");
                        if (rows.Length > 0)
                            return rows[0];
                    }
                }
                #endregion
                */

                return null;
            }
            else
            {
                rows = _moduleTable.Select(Alias.Module.Namespace + "='" + rows[0][Alias.Template.Module.ModuleID] + "'");
                if (rows.Length == 0)
                    return null;

                _mainModule = rows[0];
                if (mark == String.Empty)
                {
                    _module = rows[0];

                    #region 如果是管理类模板，判断是否是其它模块的管理页面
                    Match match = Regex.Match(_pathInTemplate, @"^/.*?/(?<ns>[a-zA-Z]+\.[a-zA-Z]+Module)/");
                    if (_isAdmin && match.Success)
                    {
                        string ns = match.Groups["ns"].Value;
                        foreach (DataRow row in _moduleTable.Rows)
                        {
                            if (ns == row[Alias.Module.Namespace].ToString())
                            {
                                _module = row;
                                break;
                            }
                        }
                    }
                    #endregion

                    return _module;
                }
                else
                {
                    return _mainModule;
                }
            }
        }
        internal DataTable GetObjectList(string ns)
        {
            if (_moduleToObjectTable == null)
                _moduleToObjectTable = new Dictionary<string, DataTable>();

            if (!_moduleToObjectTable.ContainsKey(ns))
            {
                using (AliCMS.SystemModule.Module.IObject bll = (AliCMS.SystemModule.Module.IObject)Manager.CreateObject("Module.Object", 0, "CHS", false))
                {
                    Dictionary<string, object> condition = new Dictionary<string, object>();
                    condition[Alias.Module.Object.Namespace] = ns;

                    _moduleToObjectTable.Add(ns, bll.List(-1, -1, condition, null));
                }
            }

            return _moduleToObjectTable[ns];
        }

        internal Expression CreateExpression(Tag tag, string value)
        {
            return new Expression(tag, value);
        }
        internal void ReportError(Exception exp, int index)
        {
            int start = 0;
            int counter = 1;
            int find = -1;
            while ((find = _text.IndexOf("\r\n", start, index - start)) != -1)
            {
                start = find + 2;
                counter++;
            }

            exp.Data.Add(1, counter);
            exp.Data.Add(2, index - start);
            throw exp;
        }

        private struct TagRange
        {
            internal TagRange(int index, int length, string typeName)
                : this(index, length, 0, 0, typeName)
            {
            }

            internal TagRange(int index, int length, int contentIndex, int contentLength, string typeName)
            {
                _index = index;
                _length = length;
                _contentIndex = contentIndex;
                _contentLength = contentLength;
                _typeName = typeName;
            }

            #region Properties
            internal int Index
            {
                get { return _index; }
            }
            internal int Length
            {
                get { return _length; }
            }
            internal int ContentIndex
            {
                get { return _contentIndex; }
            }
            internal int ContentLength
            {
                get { return _contentLength; }
            }
            internal string TypeName
            {
                get { return _typeName; }
            }
            #endregion

            #region Fields
            private int _index;
            private int _length;
            private int _contentIndex;
            private int _contentLength;
            private string _typeName;
            #endregion
        }
        private Tag FindParent(TagRange find, Tag start)
        {
            List<Tag> tags = null;
            if (start == null)
                tags = _tags;
            else
                tags = start.ChildTags;

            foreach (Tag tag in tags)
            {
                if (find.Index >= tag.Index && (find.Index + find.Length) <= (tag.Index + tag.Length))
                {
                    Tag parent = FindParent(find, tag);
                    if (parent == null)
                        return tag;
                    else
                        return parent;
                }
            }

            return null;
        }
        private void ParseFile()
        {
            #region 检查有无重复的ID并且ID是否由合法字符构成
            List<string> ids = new List<string>();
            MatchCollection matches = Regex.Matches(_text.ToString(), "<ali.*ID=\"(?<ID>[a-zA-Z_]\\w*)\"", RegexOptions.Compiled);
            foreach (Match match in matches)
            {
                string id = match.Groups["ID"].Value;
                if (ids.Contains(id))
                {
                    Exception exp = new Exception("lang_parse_template_id_must_unique");
                    ReportError(exp, match.Groups["ID"].Index);
                }

                ids.Add(id);
            }
            #endregion

            #region 分析模板并且准备所有标签
            List<TagRange> preparedTags = new List<TagRange>();
            matches = Regex.Matches(_text, @"(?<a><ali:(?<b>\w+\b)(\s+\w+=""[^""]*"")*\s*/?>)|(?<g><%\s?@\s?(Page|Control)\b.*?%>)|(?<h><%=(?<hc>.*?)%>)|(?<i><%If\b.*?%>)|(?<j><script\s(.| )*runat=""server""(.| )*>(?<jc>(.|\s)*?)</script>)|(?<k><%(?!@)(?!=)(?!If)(?!ElseIf)(?!Else)(?!EndIf)((?!<%=)(?!%>)(.|\s)|(?<a><%=)|(?<-a>%>))*(?(a)(?!))%>)|(?<l><%\s?@\s?Import\sNamespace=""(?<ln>.*?)"".*%>)", RegexOptions.Compiled);
            for (int i = matches.Count - 1; i >= 0; i--)
            {
                if (matches[i].Groups["a"].Success)
                {
                    int index = matches[i].Index;
                    int length = matches[i].Length;

                    string tagName = matches[i].Groups["b"].Value;
                    if (!matches[i].Value.EndsWith("/>"))
                    {
                        int start = index + length;
                        Regex re = new Regex(@"</ali:" + tagName + ">", RegexOptions.Compiled);
                        while (true)
                        {
                            Match match = re.Match(_text, start);
                            if (!match.Success)
                            {
                                Exception exp = new Exception("lang_parse_template_tag_not_correct");
                                ReportError(exp, start);
                            }

                            bool isMine = true;
                            for (int j = preparedTags.Count - 1; j >= 0; j--)
                            {
                                if (match.Index == (preparedTags[j].ContentIndex + preparedTags[j].ContentLength) && (match.Index + match.Length) == (preparedTags[j].Index + preparedTags[j].Length))
                                {
                                    isMine = false;
                                    break;
                                }

                                if (preparedTags[j].Index > match.Index)
                                    break;
                            }

                            if (isMine)
                            {
                                int contentIndex = index + length;
                                int contentLength = match.Index - contentIndex;
                                length = (match.Index + match.Length) - index;
                                preparedTags.Add(new TagRange(index, length, contentIndex, contentLength, tagName));
                                break;
                            }

                            start = match.Index + match.Length;
                        }
                    }
                    else
                    {
                        preparedTags.Add(new TagRange(index, length, tagName));
                    }
                }
                else if (matches[i].Groups["g"].Success)
                {
                    MatchCollection nameValueMaches = Regex.Matches(_text.Substring(matches[i].Index, matches[i].Length), @"\s(?<n>\w+)=""(?<v>.*?)""");
                    foreach (Match match in nameValueMaches)
                    {
                        switch (match.Groups["n"].Value)
                        {
                            case "CodeFileBaseClass":
                                _baseClass = match.Groups["v"].Value;
                                break;
                            case "PathInChannel":
                                _pathInChannel = match.Groups["v"].Value;
                                break;
                            case "RunAt":
                                _runAt = match.Groups["v"].Value;
                                break;
                            case "Object":
                                _object = match.Groups["v"].Value;
                                break;
                        }
                    }

                    preparedTags.Add(new TagRange(matches[i].Index, matches[i].Length, "PageDirective"));
                }
                else if (matches[i].Groups["h"].Success)
                {
                    preparedTags.Add(new TagRange(matches[i].Index, matches[i].Length, matches[i].Groups["hc"].Index, matches[i].Groups["hc"].Length, "OutputStatment"));
                }
                else if (matches[i].Groups["i"].Success)
                {
                    int start = matches[i].Index + matches[i].Length;
                    Regex re = new Regex(@"<%EndIf%>", RegexOptions.Compiled);
                    while (true)
                    {
                        Match match = re.Match(_text, start);
                        if (!match.Success)
                        {
                            Exception exp = new Exception("lang_parse_template_cant_find_endif");
                            ReportError(exp, matches[i].Index);
                        }

                        bool isMine = true;
                        for (int j = preparedTags.Count - 1; j >= 0; j--)
                        {
                            if (preparedTags[j].TypeName != "IfStatment")
                                continue;

                            if (match.Index > preparedTags[j].Index && match.Index < preparedTags[j].Index + preparedTags[j].Length)
                            {
                                start = preparedTags[j].Index + preparedTags[j].Length;
                                isMine = false;
                                break;
                            }
                        }

                        if (isMine)
                        {
                            int contentIndex = matches[i].Index + matches[i].Length;
                            int contentLength = match.Index - contentIndex;
                            int length = (match.Index + match.Length) - matches[i].Index;
                            preparedTags.Add(new TagRange(matches[i].Index, length, contentIndex, contentLength, "IfStatment"));
                            break;
                        }
                    }
                }
                else if (matches[i].Groups["j"].Success)
                {
                    MatchCollection ms = Regex.Matches(_text.Substring(matches[i].Index + 2, matches[i].Length - 4), @"<%=(?<a>.*?)%>", RegexOptions.Compiled);
                    foreach (Match m in ms)
                    {
                        preparedTags.Add(new TagRange(matches[i].Index + m.Index + 2, m.Length, matches[i].Index + m.Groups["a"].Index + 2, m.Groups["a"].Length, "OutputStatment"));
                    }

                    preparedTags.Add(new TagRange(matches[i].Index, matches[i].Length, matches[i].Groups["jc"].Index, matches[i].Groups["jc"].Length, "Script"));
                }
                else if (matches[i].Groups["k"].Success)
                {
                    MatchCollection ms = Regex.Matches(_text.Substring(matches[i].Index + 2, matches[i].Length - 4), @"<%=(?<a>.*?)%>", RegexOptions.Compiled);
                    foreach (Match m in ms)
                    {
                        preparedTags.Add(new TagRange(matches[i].Index + m.Index + 2, m.Length, matches[i].Index + m.Groups["a"].Index + 2, m.Groups["a"].Length, "OutputStatment"));
                    }

                    preparedTags.Add(new TagRange(matches[i].Index, matches[i].Length, matches[i].Index + 2, matches[i].Length - 4, "Code"));
                }
                else if (matches[i].Groups["l"].Success)
                {
                    string ln = matches[i].Groups["ln"].Value;
                    if (!_assemblies.Contains(ln))
                        _assemblies.Add(ln);
                }
            }
            #endregion

            if (String.IsNullOrEmpty(_runAt))
            {
                if (String.IsNullOrEmpty(_pathInChannel))
                    _runAt = "Execute";
                else
                    _runAt = "Generate";
            }

            #region 形成标签树
            bool firstAd = true;
            for (int i = preparedTags.Count - 1; i >= 0; i--)
            {
                TagRange tr = preparedTags[i];

                #region 创建Tag
                Tag parent = FindParent(tr, null);
                Tag tag = null;
                switch (tr.TypeName)
                {
                    case "Ad":
                        tag = new Ad(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        if (firstAd)
                        {
                            ((Ad)tag).FirstAd = true;
                            firstAd = false;
                        }
                        break;
                    case "Bottom":
                        tag = new Bottom(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "BottomOpen":
                        tag = new BottomOpen(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Code":
                        tag = new Code(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Col":
                        tag = new Col(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Comment":
                        tag = new Comment(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Control":
                        tag = new Control(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "CurrentPage":
                        tag = new CurrentPage(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "FirstPage":
                        tag = new FirstPage(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Get":
                        tag = new Get(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "IfStatment":
                        tag = new IfStatment(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "LastPage":
                        tag = new LastPage(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Line":
                        tag = new Line(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "List":
                        tag = new List(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Menu":
                        tag = new Menu(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Middle":
                        tag = new Middle(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "MiddleOpen":
                        tag = new MiddleOpen(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "No":
                        tag = new No(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "OutputStatment":
                        tag = new OutputStatment(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "PageDirective":
                        tag = new PageDirective(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Pagination":
                        tag = new Pagination(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Path":
                        tag = new Path(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Script":
                        tag = new Script(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Record":
                        tag = new Record(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Row":
                        tag = new Row(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Select":
                        tag = new Select(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Separator":
                        tag = new Separator(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Space":
                        tag = new Space(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Top":
                        tag = new Top(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "TopOpen":
                        tag = new TopOpen(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Tree":
                        tag = new Tree(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Yes":
                        tag = new Yes(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    case "Dict":
                        tag = new Dict(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                        break;
                    //case "Widget":
                    //    tag = new Widget(this, tr.Index, tr.Length, tr.ContentIndex, tr.ContentLength, parent);
                    //    break;
                }
                if (tag == null)
                {
                    Exception exp = new Exception("lang_parse_template_tag_not_defind");
                    exp.Data.Add(3, tr.TypeName);
                    ReportError(exp, tr.Index);
                }
                #endregion

                if (parent == null)
                    _tags.Add(tag);
                else
                    parent.ChildTags.Add(tag);
            }
            #endregion

            #region 初始化每个标签
            foreach (Tag tag in _tags)
            {
                InitTag(tag);
            }
            #endregion

            #region 解析每个标签
            foreach (Tag tag in _tags)
            {
                ParseTag(tag);
            }
            #endregion
        }
        private void ParseTag(Tag tag)
        {
            foreach (Tag childTag in tag.ChildTags)
            {
                ParseTag(childTag);
            }

            tag.Parse();
        }
        private void InitTag(Tag tag)
        {
            tag.Init();

            foreach (Tag childTag in tag.ChildTags)
            {
                InitTag(childTag);
            }
        }

        private void WriteCSFile(string csFile)
        {
            _tagCode.Remove(0, _tagCode.Length);

            WriteChannelCode();
            WriteFunctionCode();
            WriteVarCode();
            Tag paginationTag = null;
            foreach (Tag tag in _tags)
            {
                if (tag is Pagination)
                    paginationTag = tag;

                WriteTagCode(tag);
            }

            Manager.MakeSureFolderExist(System.IO.Path.GetDirectoryName(csFile));

            #region 写入using assembly
            StreamWriter sw = new StreamWriter(csFile, false, Encoding.UTF8);
            foreach (string assembly in _assemblies)
            {
                sw.WriteLine("using " + assembly + ";");
            }

            if (_module != null)
            {
                #region 第一级命名空间也引用起来。第一级是公司名称或者项目名称，第二级为模块名称。第一级放公共代码，类似AliCMS.Base程序级里的AliCMS。所有的接口放在这里了
                string ns = _module[Alias.Module.Namespace].ToString();
                int slash = ns.IndexOf('.');
                if (slash != -1)
                {
                    ns = ns.Substring(0, slash);
                    if (!_assemblies.Contains(ns))
                        sw.WriteLine("using " + ns + ";");
                }
                #endregion

                sw.WriteLine("using " + _module[Alias.Module.Namespace] + ";");
            }
            #endregion

            sw.WriteLine("public partial class " + _className + " : " + _baseClass);
            sw.WriteLine("{");
            sw.WriteLine("public " + _className + "()");
            sw.WriteLine(": base(\"" + _pathInTemplate + "\")");
            sw.WriteLine("{}");
            sw.WriteLine("protected XmlDocument _xmlTemplate;");
            sw.WriteLine("protected override void OnInit(EventArgs e)");
            sw.WriteLine("{");
            sw.WriteLine("base.OnInit(e);");
            sw.WriteLine("_xmlTemplate = XmlData.GetXmlDocument();");
            sw.WriteLine(@"if (!String.IsNullOrEmpty(Request.QueryString[""GetPageCount""]))
                            {
                                Response.Write(" + (paginationTag == null ? "1" : paginationTag.UniqueName) + @");
                                Response.End();
                            }
                        ");
            if (!_debug && Regex.IsMatch(_text, "<%@ OutputCache\\b.*%>"))
                sw.WriteLine("Response.AddCacheItemDependency(\"ClearAllCache\");");
            sw.WriteLine("}");
            sw.Write(_tagCode);
            sw.WriteLine("}");
            sw.Close();
            sw = null;
        }
        private void WriteTagCode(Tag tag)
        {
            if (tag.ResultCode != null && !(tag is Code) && !(tag is IfStatment) && !(tag is OutputStatment))
                _tagCode.Append(tag.ResultCode);

            foreach (Tag child in tag.ChildTags)
            {
                WriteTagCode(child);
            }
        }
        private void WriteVarCode()
        {
            foreach (string key in _usedVars.Keys)
            {
                switch (key)
                {
                    case "Footer":
                        _tagCode.Append(@"protected string Footer
                                            {
                                                get
                                                {
                                                    if (String.IsNullOrEmpty(Channel[AliCMS.SystemModule.Alias.Channel.Footer].ToString()))
                                                        return Manager.Site[AliCMS.SystemModule.Alias.InstanceConfig.Footer + PageLang].ToString();
                                                    else
                                                        return Channel[AliCMS.SystemModule.Alias.Channel.Footer].ToString();
                                                }
                                            }
                            "
                            );
                        break;
                    case "Notice":
                        _tagCode.Append(@"protected string Notice
                                            {
                                                get
                                                {
                                                    if (String.IsNullOrEmpty(Channel[AliCMS.SystemModule.Alias.Channel.Notice].ToString()))
                                                        return Manager.Site[AliCMS.SystemModule.Alias.InstanceConfig.Notice + PageLang].ToString();
                                                    else
                                                        return Channel[AliCMS.SystemModule.Alias.Channel.Notice].ToString();
                                                }
                                            }
                            "
                            );
                        break;
                    case "StatCode":
                        _tagCode.Append(@"protected string StatCode
                                            {
                                                get
                                                {
                                                    if (String.IsNullOrEmpty(Channel[AliCMS.SystemModule.Alias.Channel.StatCode].ToString()))
                                                        return Manager.Site[AliCMS.SystemModule.Alias.InstanceConfig.StatCode + PageLang].ToString();
                                                    else
                                                        return Channel[AliCMS.SystemModule.Alias.Channel.StatCode].ToString();
                                                }
                                            }
                            "
							);
                        break;
                    case "Logo":
                        _tagCode.Append(@"protected string Logo
                                            {
                                                get
                                                {
                                                    if (String.IsNullOrEmpty(Channel[AliCMS.SystemModule.Alias.Channel.Logo].ToString()))
                                                        return Manager.Site[AliCMS.SystemModule.Alias.InstanceConfig.Logo + PageLang].ToString();
                                                    else
                                                        return Channel[AliCMS.SystemModule.Alias.Channel.Logo].ToString();
                                                }
                                            }
                            "
                            );
                        break;
                    case "Link":
                        _tagCode.Append(@"protected string Link
                                            {
                                                get
                                                {
                                                    if (String.IsNullOrEmpty(Channel[AliCMS.SystemModule.Alias.Channel.Link].ToString()))
                                                        return Manager.Site[AliCMS.SystemModule.Alias.InstanceConfig.Link + PageLang].ToString();
                                                    else
                                                        return Channel[AliCMS.SystemModule.Alias.Channel.Link].ToString();
                                                }
                                            }
                            "
                            );
                        break;
                    case "MetaKeywords":
                        StringBuilder metaKeywords = new StringBuilder();
                        foreach (Tag tag in _tags)
                        {
                            if (!(tag is Get))
                                continue;

                            Get get = tag as Get;
                            if (get.ForMeta)
                            {
                                object objectID = null;
                                DataRow[] rows = Manager.Objects.Select(Alias.Module.Object.Namespace + "='" + get.Module[Alias.Module.Namespace] + "' and FullName='" + get.Object + "'");
                                if (rows.Length == 1)
                                {
                                    string id = String.IsNullOrEmpty(get.Id) ? get.UniqueName + "ID" : get.Id;
                                    objectID = rows[0][Alias.Module.Object.ID];

                                    rows = Manager.Properties.Select(Alias.Module.Object.Property.ObjectID + "='" + objectID + "' and " + Alias.Module.Object.Property.Name + "='MetaKeywords'");
                                    if (rows.Length == 1)
                                    {
                                        metaKeywords.Append(@"
                                                    if (!String.IsNullOrEmpty(" + id + @"[" + get.Module[Alias.Module.Namespace] + @".Alias." + get.Object + @".MetaKeywords].ToString()))
                                                        result.Append(" + id + @"[" + get.Module[Alias.Module.Namespace] + @".Alias." + get.Object + @".MetaKeywords].ToString());
                                                    else
                                                    "
                                                );
                                    }

                                    rows = Manager.Properties.Select(Alias.Module.Object.Property.ObjectID + "='" + objectID + "' and " + Alias.Module.Object.Property.IsMeta + "=true");
                                    if (rows.Length > 0)
                                        metaKeywords.Append("result.Append(");

                                    for (int i = 0; i < rows.Length; i++)
                                    {
                                        if (i > 0)
                                            metaKeywords.Append(" + \" \" + ");

                                        metaKeywords.Append(id + "[" + get.Module[Alias.Module.Namespace] + @".Alias." + get.Object + @"." + rows[i][Alias.Module.Object.Property.Name] + "]");
                                    }

                                    if (rows.Length > 0)
                                        metaKeywords.Append(");");
                                }
                            }
                        }

                        if (IsMultiSite)
                        {
                            metaKeywords.Append(@"
                                    if (SubChannel != null && !String.IsNullOrEmpty(SubChannel[AliCMS.SiteModule.Alias.Channel.MetaKeywords].ToString()))
                                    {
                                        if (result.Length > 0)
                                            result.Append("" , "");
                                        result.Append(SubChannel[AliCMS.SiteModule.Alias.Channel.MetaKeywords]);
                                    }

                                    if (!String.IsNullOrEmpty(SubSite[AliCMS.SiteModule.Alias.Site.MetaKeywords].ToString()))
                                    {
                                        if (result.Length > 0)
                                            result.Append("" , "");
                                        result.Append(SubSite[AliCMS.SiteModule.Alias.Site.MetaKeywords]);
                                    }
                                    "
										);
                        }
                        else
                        {
                            metaKeywords.Append(@"
                                    if (!String.IsNullOrEmpty(Channel[AliCMS.SystemModule.Alias.Channel.MetaKeywords].ToString()))
                                    {
                                        if (result.Length > 0)
                                            result.Append("" , "");
                                        result.Append(Channel[AliCMS.SystemModule.Alias.Channel.MetaKeywords]);
                                    }

                                    if (!String.IsNullOrEmpty(Manager.Site[AliCMS.SystemModule.Alias.InstanceConfig.MetaKeywords + PageLang].ToString()))
                                    {
                                        if (result.Length > 0)
                                            result.Append("" , "");
                                        result.Append(Manager.Site[AliCMS.SystemModule.Alias.InstanceConfig.MetaKeywords + PageLang]);
                                    }
                                    "
                                        );
                        }

                        _tagCode.Append(@"protected string MetaKeywords
                                            {
                                                get
                                                {
                                                    StringBuilder result = new StringBuilder();
                                                    " + metaKeywords + @"
                                                    return result.ToString();
                                                }
                                            }
                            "
                            );
                        break;
                    case "MetaDescription":
                        StringBuilder metaDescription = new StringBuilder();
                        foreach (Tag tag in _tags)
                        {
                            if (!(tag is Get))
                                continue;

                            Get get = tag as Get;
                            if (get.ForMeta)
                            {
                                object objectID = null;
                                DataRow[] rows = Manager.Objects.Select(Alias.Module.Object.Namespace + "='" + get.Module[Alias.Module.Namespace] + "' and FullName='" + get.Object + "'");
                                if (rows.Length == 1)
                                {
                                    string id = String.IsNullOrEmpty(get.Id) ? get.UniqueName + "ID" : get.Id;
                                    objectID = rows[0][Alias.Module.Object.ID];

                                    rows = Manager.Properties.Select(Alias.Module.Object.Property.ObjectID + "='" + objectID + "' and " + Alias.Module.Object.Property.Name + "='MetaDescription'");
                                    if (rows.Length == 1)
                                    {
                                        metaDescription.Append(@"
                                                    if (!String.IsNullOrEmpty(" + id + @"[" + get.Module[Alias.Module.Namespace] + @".Alias." + get.Object + @".MetaDescription].ToString()))
                                                        result.Append(" + id + @"[" + get.Module[Alias.Module.Namespace] + @".Alias." + get.Object + @".MetaDescription].ToString());
                                                    else
                                                    "
                                                );
                                    }

                                    rows = Manager.Properties.Select(Alias.Module.Object.Property.ObjectID + "='" + objectID + "' and " + Alias.Module.Object.Property.IsMeta + "=true");
                                    if (rows.Length > 0)
                                        metaDescription.Append("result.Append(");
                                    for (int i = 0; i < rows.Length; i++)
                                    {
                                        if (i > 0)
                                            metaDescription.Append(" + \" \" + ");

                                        metaDescription.Append(id + "[" + get.Module[Alias.Module.Namespace] + @".Alias." + get.Object + @"." + rows[i][Alias.Module.Object.Property.Name] + "]");
                                    }

                                    if (rows.Length > 0)
                                        metaDescription.Append(");");
                                }
                            }
                        }

                        if (IsMultiSite)
                        {
                            metaDescription.Append(@"
                                        if (SubChannel != null && !String.IsNullOrEmpty(SubChannel[AliCMS.SiteModule.Alias.Channel.MetaDescription].ToString()))
                                        {
                                            if (result.Length > 0)
                                                result.Append("" , "");
                                            result.Append(SubChannel[AliCMS.SiteModule.Alias.Channel.MetaDescription]);
                                        }

                                        if (!String.IsNullOrEmpty(SubSite[AliCMS.SiteModule.Alias.Site.MetaDescription].ToString()))
                                        {
                                            if (result.Length > 0)
                                                result.Append("" , "");
                                            result.Append(SubSite[AliCMS.SiteModule.Alias.Site.MetaDescription]);
                                        }
                                        "
										);
                        }
                        else
                        {
                            metaDescription.Append(@"
                                        if (!String.IsNullOrEmpty(Channel[AliCMS.SystemModule.Alias.Channel.MetaDescription].ToString()))
                                        {
                                            if (result.Length > 0)
                                                result.Append("" , "");
                                            result.Append(Channel[AliCMS.SystemModule.Alias.Channel.MetaDescription]);
                                        }

                                        if (!String.IsNullOrEmpty(Manager.Site[AliCMS.SystemModule.Alias.InstanceConfig.MetaDescription + PageLang].ToString()))
                                        {
                                            if (result.Length > 0)
                                                result.Append("" , "");
                                            result.Append(Manager.Site[AliCMS.SystemModule.Alias.InstanceConfig.MetaDescription + PageLang]);
                                        }
                                        "
                                        );
                        }

                        _tagCode.Append(@"protected string MetaDescription
                                            {
                                                get
                                                {
                                                    StringBuilder result = new StringBuilder();
                                                    " + metaDescription + @"
                                                    return result.ToString();
                                                }
                                            }
                            "
                            );
                        break;
                }
            }
        }
        private void WriteChannelCode()
        {
            string code = @"
                                protected DataRow {#Mark#}Channel
                                {
                                    get
                                    {
                                        if (_{#Mark#}Channel == null)
                                            _{#Mark#}Channel = " + (IsMultiSite ? "GetBindingChannel(SubChannel, \"{#Mark#}\")" : "Manager.GetExtraInstance(Channel, \"{#Mark#}\")") + @";

                                        return _{#Mark#}Channel;
                                    }
                                }
                                private DataRow _{#Mark#}Channel;

                            ";
            foreach (string mark in _usedChannel)
            {
                #region 跳过系统模块
                if (mark == "System")
                    continue;
                #endregion

                #region 站群下，跳过当前栏目
                if (IsMultiSite && mark == "")
                    continue;
                #endregion

                #region 当Mark为Guid时，表示Instance的ID。主要用在“应用”上。通过可视编辑的方式选择自己的应用，对应的实例ID放在Mark里。
                if (Regex.IsMatch(mark, @"\{?[a-fA-F0-9]{8}(-?[a-fA-F0-9]{4}){3}-?[a-fA-F0-9]{12}\}?"))
                    continue;
                #endregion

                _tagCode.Append(code.Replace("{#Mark#}", mark));
            }
        }
        private void WriteFunctionCode()
        {
            foreach (string key in _usedFunctions)
            {
                switch (key)
                {
                    case "JsPath":
                        _tagCode.Append(@"protected string GetJsPath(object file)
                                            {
                                                string path = JsPath + file;
                                                if (!System.IO.File.Exists(Manager.MapPath(path)))
                                                {
                                                    //检查上一层目录
                                                    int end = path.LastIndexOf(""/js/"");
                                                    int start = path.LastIndexOf('/', end - 1);
                                                    string websiteJsPath = path.Remove(start, end - start);
                                                    if (System.IO.File.Exists(Manager.MapPath(websiteJsPath)))
                                                        return websiteJsPath;

                                                    //不存在，则检查再上一层目录
                                                    end = websiteJsPath.LastIndexOf(""/js/"");
                                                    start = websiteJsPath.LastIndexOf('/', end - 1);
                                                    websiteJsPath = websiteJsPath.Remove(start, end - start);
                                                    if (System.IO.File.Exists(Manager.MapPath(websiteJsPath)))
                                                        return websiteJsPath;
                                                }

                                                return path;
                                            }
                            "
                            );
                        break;
                    case "CssPath":
                        _tagCode.Append(@"protected string GetCssPath(object file)
                                            {
                                                string path = CssPath + file;
                                                if (!System.IO.File.Exists(Manager.MapPath(path)))
                                                {
                                                    //检查上一层目录
                                                    int end = path.LastIndexOf(""/css/"");
                                                    end = path.LastIndexOf('/', end - 1);
                                                    end = path.LastIndexOf('/', end - 1);
                                                    int start = path.LastIndexOf('/', end - 1);
                                                    string websiteCssPath = path.Remove(start, end - start);
                                                    if (System.IO.File.Exists(Manager.MapPath(websiteCssPath)))
                                                        return websiteCssPath;

                                                    //不存在，则检查再上一层目录
                                                    end = websiteCssPath.LastIndexOf(""/css/"");
                                                    end = websiteCssPath.LastIndexOf('/', end - 1);
                                                    end = websiteCssPath.LastIndexOf('/', end - 1);
                                                    start = websiteCssPath.LastIndexOf('/', end - 1);
                                                    websiteCssPath = websiteCssPath.Remove(start, end - start);
                                                    if (System.IO.File.Exists(Manager.MapPath(websiteCssPath)))
                                                        return websiteCssPath;
                                                }

                                                return path;
                                            }
                            "
                            );
                        break;
                }
            }
        }

        private void WriteAspxFile(string codeFile)
        {
            StringBuilder page = new StringBuilder(_text);
            string pageDirective = null;
            Match match = null;
            MatchCollection matches = null;
            int index = 0;

            #region 获取路径
            string ext = null;
            if (_pathInTemplate.EndsWith(".e"))
                ext = System.IO.Path.GetExtension(_pathInTemplate.Substring(0, _pathInTemplate.Length - 2));
            else
                ext = System.IO.Path.GetExtension(_pathInTemplate);
            string path = Manager.GetCachedTemplatePath(_veCachePrefix + _templatePath, _targetLang, _debug) + _pathInTemplate.Substring(0, _pathInTemplate.LastIndexOf(".dwt")) + ext;
            #endregion

            #region 生成aspx标签
            for (int i = _tags.Count - 1; i >= 0; i--)
            {
                Tag tag = _tags[i];

                if (tag is PageDirective)
                {
                    pageDirective = _text.Substring(tag.Index, tag.Length);
                    pageDirective = Regex.Replace(pageDirective, "(PathInChannel|Pagination|PageSize|RecordCount|Object|RunAt|CodeFileBaseClass|Mark)=\"(?<v>.*?)\"", "");
                    pageDirective = pageDirective.Insert(pageDirective.Length - 2, "CodeFile=\"" + codeFile + "\" Inherits=\"" + _className + "\"");
                }

                page.Remove(tag.Index, tag.Length);

                if (tag is OutputStatment)
                    page.Insert(tag.Index, "<%=" + tag.ResultCode + "%>");
                else if (tag is IfStatment)
                    page.Insert(tag.Index, "<%\r\n" + tag.ResultCode + "%><%=" + tag.UniqueName + "%>");
                else if (tag is Code)
                    page.Insert(tag.Index, tag.ResultCode);
                else if (tag.ResultCode != null && tag.ResultXml != null && Regex.IsMatch(tag.ResultCode, "protected string " + tag.UniqueName + @"\s+{\s+get\s+"))
                    page.Insert(tag.Index, "<%=" + tag.UniqueName + "%>");
            }
            #endregion

            #region 生成Xml数据
            StringBuilder data = new StringBuilder("<asp:XmlDataSource ID=\"XmlData\" runat=\"server\"><Data><Template>");
            foreach (Tag tag in _tags)
            {
                WriteTagXml(data, tag);
            }
            data.Append("</Template></Data></asp:XmlDataSource>");

            int endBodyIndex = page.ToString().LastIndexOf("</body>", page.Length);
            if (endBodyIndex == -1)
                page.Append(data);
            else
                page.Insert(endBodyIndex, data);
            #endregion

            #region page指令
            if (pageDirective == null)
            {
                if (_isControl)
                    page.Insert(0, "<%@ Control CodeFile=\"" + codeFile + "\" Inherits=\"" + _className + "\"%>\r\n");
                else
                    page.Insert(0, "<%@ Page CodeFile=\"" + codeFile + "\" Inherits=\"" + _className + "\"%>\r\n");
            }
            else
            {
                page.Insert(0, pageDirective);
            }
            #endregion

            #region 调试模式下，删除缓存设置
            if (_debug)
            {
                match = Regex.Match(page.ToString(), "<%@ OutputCache\\b.*%>", RegexOptions.IgnoreCase);
                if (match.Success)
                    page.Remove(match.Index, match.Length);
            }
            #endregion

            #region 可视编辑状态下，添加相关代码
            if (_vedit)
            {
                #region 添加IE兼容代码
                match = Regex.Match(page.ToString(), @"</head>", RegexOptions.IgnoreCase);
                if (match.Success)
                    page.Insert(match.Index, "<script>var _curImagePath = \"<%=ImagePath%>\";var _veChannelPath = \"" + _veChannelPath + "\";var _veOrgPage = \"" + _veSource + "\";var _veCurPage = \"" + _veTarget + "\";</script><!--[if IE]><script>document.createElement(\"widget\");document.createElement(\"text\");</script><![endif]-->");
                #endregion

                #region 插入vedit.js
                match = Regex.Match(page.ToString(), @"</body>\s*</html>\s*$", RegexOptions.IgnoreCase);
                if (match.Success)
                    page.Insert(match.Index, "<script src=\"" + _veTemplatePath + "js/vedit.js\"></script>");
                #endregion
            }
            else
            {
                #region 如果页面有widget标签
                if (page.ToString().IndexOf("</widget>") != -1)
                {
                    #region 加上兼容代码
                    match = Regex.Match(page.ToString(), @"</head>", RegexOptions.IgnoreCase);
                    if (match.Success)
                        page.Insert(match.Index, "<!--[if IE]><script>document.createElement(\"widget\");</script><![endif]-->");
                    #endregion

                    #region 删除widget标签的json属性（为了方便和避免冲突，他的值假设超过50个字符）
                    matches = Regex.Matches(page.ToString(), @"\s+json=""[^""]{50,}""");
                    for (int i = matches.Count - 1; i >= 0; i--)
                    {
                        page.Remove(matches[i].Index, matches[i].Length);
                    }
                    #endregion

                    #region 删除text标签
                    matches = Regex.Matches(page.ToString(), @"</?text>");
                    for (int i = matches.Count - 1; i >= 0; i--)
                    {
                        page.Remove(matches[i].Index, matches[i].Length);
                    }
                    #endregion
                }
                #endregion
            }
            #endregion

            #region 处理License
            if (!_isControl)
            {
                #region 检查并生成标志
				string statistics = "";//暂时不放统计："<script src=\"http://www.alibaza.com/external/alicms_stat.js\"></script>";
				string backTitle = "";//暂时不放后台标题：" - powered by AliCMS " + Manager.Site[Alias.InstanceConfig.SystemVersion];
				string backAd = "";//暂时不放后台广告："<script src=\"http://www.alibaza.com/external/alicms_login.js\"></script>";
				string frontTitle = "";//暂时不放前台标题：" - powered by AliCMS " + Manager.Site[Alias.InstanceConfig.SystemVersion];
                string frontFooter = "<a href=\"http://www.alicms.cn\" target=\"_blank\" style=\"display:block;line-height:20px;font-family:arial;font-size:12px;text-align:center\">powered by <strong>AliCMS " + Manager.Site[Alias.InstanceConfig.SystemVersion] + "</strong> www.alicms.cn</a>";

                bool backTitleRemoved = false;
                bool backAdRemoved = false;
                bool frontTitleRemoved = false;
                bool frontFooterRemoved = false;

                try
                {
                    string mark = "AliCMS Key";
                    string serverName = HttpContext.Current.Request.ServerVariables["SERVER_NAME"];
                    XmlDocument xmlDoc = new XmlDocument();

                    string[] files = Directory.GetFiles(Manager.MapPath(Manager.GetWebPath()), "*.key", SearchOption.TopDirectoryOnly);
                    foreach (string file in files)
                    {
                        StreamReader sr = File.OpenText(file);
                        string all = sr.ReadToEnd();
                        sr.Close();
                        sr = null;

                        if (!all.StartsWith(mark))
                            continue;

                        string original = RC2Decrypt(all.Substring(mark.Length), "مۇرات", "ئىلغار");

                        xmlDoc.LoadXml(original);

                        string domain = xmlDoc.SelectSingleNode("//Domain").InnerText;
                        if (serverName.EndsWith(domain))
                        {
                            XmlNode node = xmlDoc.SelectSingleNode("//BackTitle");
                            if (node != null && node.Attributes["Removed"] != null && Convert.ToBoolean(node.Attributes["Removed"].Value) && Convert.ToDateTime(node.Attributes["Expire"].Value) > DateTime.Now)
                            {
                                backTitleRemoved = true;
                            }

                            node = xmlDoc.SelectSingleNode("//BackAd");
                            if (node != null && node.Attributes["Removed"] != null && Convert.ToBoolean(node.Attributes["Removed"].Value) && Convert.ToDateTime(node.Attributes["Expire"].Value) > DateTime.Now)
                            {
                                backAdRemoved = true;
                            }

                            node = xmlDoc.SelectSingleNode("//FrontTitle");
                            if (node != null && node.Attributes["Removed"] != null && Convert.ToBoolean(node.Attributes["Removed"].Value) && Convert.ToDateTime(node.Attributes["Expire"].Value) > DateTime.Now)
                            {
                                frontTitleRemoved = true;
                            }

                            node = xmlDoc.SelectSingleNode("//FrontFooter");
                            if (node != null && node.Attributes["Removed"] != null && Convert.ToBoolean(node.Attributes["Removed"].Value) && Convert.ToDateTime(node.Attributes["Expire"].Value) > DateTime.Now)
                            {
                                frontFooterRemoved = true;
                            }

                            break;
                        }
                    }
                }
                catch
                {
                }
                finally
                {
                    if (backTitleRemoved) backTitle = null;
                    if (backAdRemoved) backAd = null;
                    if (frontTitleRemoved) frontTitle = null;
                    if (frontFooterRemoved) frontFooter = null;
                }

                backAd += statistics;
                #endregion

                if (_mainModule != null && (_mainModule[Alias.Module.Namespace].ToString() == "AliCMS.SystemModule"))
                {
                    #region 后台标题
                    if (backTitle != null)
                    {
                        index = page.ToString().IndexOf("</title>", 0, StringComparison.InvariantCultureIgnoreCase);
                        if (index == -1)
                        {
                            index = page.ToString().IndexOf("<head>", 0, StringComparison.InvariantCultureIgnoreCase);
                            if (index != -1)
                                page.Insert(index + 6, "<title>" + backTitle + "</title>");
                            else if (!System.IO.Path.GetFileName(_pathInTemplate).StartsWith("ajax_"))
                                page.Insert(0, "<title>" + backTitle + "</title>");
                        }
                        else
                        {
                            page.Insert(index, backTitle);
                        }
                    }
                    #endregion
                    #region 后台广告
                    if (backAd != null && _pathInTemplate.Equals("login.dwt.aspx", StringComparison.InvariantCultureIgnoreCase))
                    {
                        index = page.ToString().IndexOf("</body>", 0, StringComparison.InvariantCultureIgnoreCase);
                        if (index == -1)
                            page.Append(backAd);
                        else
                            page.Insert(index, backAd);
                    }
                    #endregion
                }
                else
                {
                    #region 前台标题
                    if (frontTitle != null)
                    {
                        index = page.ToString().IndexOf("</title>", 0, StringComparison.InvariantCultureIgnoreCase);
                        if (index == -1)
                        {
                            index = page.ToString().IndexOf("<head>", 0, StringComparison.InvariantCultureIgnoreCase);
                            if (index != -1)
                                page.Insert(index + 6, "<title>" + frontTitle + "</title>");
                            else if (!System.IO.Path.GetFileName(_pathInTemplate).StartsWith("ajax_"))
                                page.Insert(0, "<title>" + frontTitle + "</title>");
                        }
                        else
                        {
                            page.Insert(index, frontTitle);
                        }
                    }
                    #endregion
                    #region 前台脚注
                    if (frontFooter != null)
                    {
                        match = Regex.Match(page.ToString(), @"</body>\s*</html>\s*$", RegexOptions.IgnoreCase);
                        if (match.Success)
                            page.Insert(match.Index, frontFooter);
                        else if (!System.IO.Path.GetFileName(_pathInTemplate).StartsWith("ajax_"))
                            page.Append(frontFooter);
                    }
                    #endregion
                }
            }
            #endregion

            #region 写入Generator
            index = page.ToString().IndexOf("<head>", 0, StringComparison.InvariantCultureIgnoreCase);
            if (index != -1)
                page.Insert(index + 6, "<meta name=\"generator\" content=\"AliCMS(阿里CMS)\" />");
            #endregion

            #region 处理ascx
            matches = Regex.Matches(page.ToString(), @"<%@\s*Register(.| )*Src=""(?<v>.*\.dwt\.ascx)""(.| )*%>");
            for (int i = matches.Count - 1; i >= 0; i--)
            {
                string ascx = matches[i].Groups["v"].Value.Replace(".dwt.ascx", ".ascx");
                string ascxTemplatePath = _templatePath;

                #region 考虑用户控件在网站模板下
                int def = Regex.Matches(ascx, "../").Count - Regex.Matches(_pathInTemplate, "/").Count;
                ascxTemplatePath = ascxTemplatePath.TrimEnd('/');
                while (def > 0 && ascxTemplatePath.IndexOf("/") != -1)
                {
                    ascxTemplatePath = System.IO.Path.GetDirectoryName(ascxTemplatePath).Replace('\\', '/');
                    ascx = ascx.Remove(0, 3);
                    def--;
                }
                #endregion

                string dirInTemplate = null;
                #region 考虑管理模板，并且命名空间下
                if (_isAdmin && _pathInTemplate.StartsWith("/"))
                {
                    int pageIndex = _pathInTemplate.IndexOf("/page/");
                    dirInTemplate = System.IO.Path.GetDirectoryName(_pathInTemplate.Substring(pageIndex + 1));
                }
                #endregion
                else
                {
                    dirInTemplate = System.IO.Path.GetDirectoryName(_pathInTemplate);
                }

                string cachedTemplateFullPath = Manager.GetCachedTemplatePath(ascxTemplatePath, _targetLang, _debug);
                ascx = System.IO.Path.Combine(cachedTemplateFullPath + dirInTemplate, ascx);

                #region 替换原来的值
                page.Remove(matches[i].Groups["v"].Index, matches[i].Groups["v"].Length);
                page.Insert(matches[i].Groups["v"].Index, ascx);
                #endregion
            }
            #endregion

            #region ClearScriptComment, ClearHtmlComment, ClearWhiteSpace
            if (Convert.ToBoolean(Manager.Site[Alias.InstanceConfig.ClearScriptComment]) || Convert.ToBoolean(Manager.Site[Alias.InstanceConfig.ClearHtmlComment]))
            {
                Regex re = null;
                MatchCollection comments = null;

                MatchCollection scripts = Regex.Matches(page.ToString(), @"<script[^<]*?>(?<a>(.|\s)*?)</script>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
                if (Convert.ToBoolean(Manager.Site[Alias.InstanceConfig.ClearScriptComment]))
                {
                    re = new Regex(@"(/\*(.|\s)*?\*/)|((?<!(https?:)|(""))//(?!-->).*)", RegexOptions.Compiled);
                    for (int i = scripts.Count - 1; i >= 0; i--)
                    {
                        StringBuilder script = new StringBuilder(scripts[i].Groups["a"].Value);
                        comments = re.Matches(script.ToString());
                        for (int j = comments.Count - 1; j >= 0; j--)
                        {
                            script.Remove(comments[j].Index, comments[j].Length);
                        }

                        page.Remove(scripts[i].Groups["a"].Index, scripts[i].Groups["a"].Length);
                        page.Insert(scripts[i].Groups["a"].Index, script);
                    }
                }

                if (Convert.ToBoolean(Manager.Site[Alias.InstanceConfig.ClearHtmlComment]))
                {
                    if (Convert.ToBoolean(Manager.Site[Alias.InstanceConfig.ClearScriptComment]))
                        scripts = Regex.Matches(page.ToString(), @"<script[^<]*>(?<a>(.|\s)*?)</script>", RegexOptions.Compiled | RegexOptions.IgnoreCase);

                    re = new Regex(@"<!--(?!\[if)(.|\s)*?-->", RegexOptions.Compiled);
                    comments = re.Matches(page.ToString());
                    for (int j = comments.Count - 1; j >= 0; j--)
                    {
                        int i = scripts.Count - 1;
                        for (; i >= 0; i--)
                        {
                            if (comments[j].Index > scripts[i].Index && comments[j].Index < scripts[i].Index + scripts[i].Length)
                                break;
                        }

                        if (i >= 0)
                            continue;

                        page.Remove(comments[j].Index, comments[j].Length);
                    }
                }
            }

            if (Convert.ToBoolean(Manager.Site[Alias.InstanceConfig.ClearWhiteSpace]))
            {
                string clearedPage = Regex.Replace(page.ToString(), @"\s{2,}", " ");
                clearedPage = Regex.Replace(clearedPage, @"(\]\]>)\s+", "$1");
                page.Remove(0, page.Length);
                page.Append(Regex.Replace(clearedPage, @"\s+(<!\[CDATA\[)", "$1"));
            }
            #endregion

            #region 翻译内容
            if (_targetLang != _lang)
                TranslateContent(page, _lang, _targetLang);
            #endregion

            #region 处理{标识}
            matches = Regex.Matches(page.ToString(), @"\{(?<v>[a-zA-Z0-9_]+)\}");
            for (int i = matches.Count - 1; i >= 0; i--)
            {
                string name = matches[i].Groups["v"].Value;
                foreach (DataRow word in Words)
                {
                    if (word[Alias.Template.Dictionary.Name].ToString() == name)
                    {
                        page.Remove(matches[i].Index, matches[i].Length);
                        page.Insert(matches[i].Index, word[Alias.Template.Dictionary.To]);
                        break;
                    }
                }
            }
            #endregion

            #region 写入文件
            path = Manager.MapPath(path);
            Manager.MakeSureFolderExist(System.IO.Path.GetDirectoryName(path));

            StreamWriter sw = new StreamWriter(path, false, Encoding.UTF8);
            sw.Write(page.ToString());
            sw.Close();
            sw = null;
            #endregion
        }
        private void WriteTagXml(StringBuilder file, Tag tag)
        {
            if (tag.ResultXml != null)
            {
                file.Append("<" + tag.UniqueName + ">");
                file.Append(tag.ResultXml);
                file.Append("</" + tag.UniqueName + ">");
            }

            foreach (Tag child in tag.ChildTags)
            {
                WriteTagXml(file, child);
            }
        }

        private void TranslateContent(StringBuilder content, string from, string to)
        {
            if (from == to)
                return;

            foreach (DataRow row in Words)
            {
                if (String.IsNullOrEmpty(Convert.ToString(row[Alias.Template.Dictionary.Name])) && !String.IsNullOrEmpty(Convert.ToString(row[Alias.Template.Dictionary.From])))
                    content.Replace(row[Alias.Template.Dictionary.From].ToString(), row[Alias.Template.Dictionary.To].ToString());
            }

            #region 语言相关图片
            content.Replace(from + ".", to + ".");
            #endregion

            TranslateContentHtml(content, from, to);
        }
        internal static void TranslateContentHtml(StringBuilder content, string from, string to)
        {
            if (from == to)
                return;

            DataTable languages = null;
            IManager manager = (IManager)HttpContext.Current.Application["Manager"];
            using (IInstanceConfig bll = (IInstanceConfig)manager.CreateObject("InstanceConfig", 0, null, false))
            {
                languages = bll.GetLanguageSettings();
            }

            DataRow fromRow = languages.Select(Alias.Language.Ab + "='" + from + "'")[0];
            DataRow toRow = languages.Select(Alias.Language.Ab + "='" + to + "'")[0];
            if (fromRow[Alias.Language.Direction].ToString() != toRow[Alias.Language.Direction].ToString())
            {
                string f, t;
                if (fromRow[Alias.Language.Direction].ToString() == "ltr")
                {
                    f = "left";
                    t = "right";
                }
                else
                {
                    f = "right";
                    t = "left";
                }

                #region dir="left" OR dir="right"
                content.Replace("dir=\"" + f + "\"", "dir=\"" + f + "_temp\"");
                content.Replace("dir=\"" + t + "\"", "dir=\"" + f + "\"");
                content.Replace("dir=\"" + f + "_temp\"", "dir=\"" + t + "\"");
                #endregion

                #region direction="left" OR direction="right"
                content.Replace("direction=\"" + f + "\"", "direction=\"" + f + "_temp\"");
                content.Replace("direction=\"" + t + "\"", "direction=\"" + f + "\"");
                content.Replace("direction=\"" + f + "_temp\"", "direction=\"" + t + "\"");
                #endregion

                #region Frameset
                MatchCollection matches = Regex.Matches(content.ToString(), @"<frameset.*cols=""(?<l>[\d\*]+),(?<r>[\d\*]+)"".*?>(?<f>(.|\s)*?)</frameset>");
                for (int i = matches.Count - 1; i >= 0; i--)
                {
                    content.Remove(matches[i].Groups["r"].Index, matches[i].Groups["r"].Length);
                    content.Insert(matches[i].Groups["r"].Index, matches[i].Groups["l"].Value);

                    content.Remove(matches[i].Groups["l"].Index, matches[i].Groups["l"].Length);
                    content.Insert(matches[i].Groups["l"].Index, matches[i].Groups["r"].Value);

                    MatchCollection frames = Regex.Matches(matches[i].Groups["f"].Value, "<frame.*?/>");
                    if (frames.Count == 2)
                    {
                        content.Remove(matches[i].Groups["f"].Index, matches[i].Groups["f"].Length);
                        content.Insert(matches[i].Groups["f"].Index, frames[1].Value + frames[0].Value);
                    }
                }
                #endregion
            }
        }

        private string RC2Decrypt(string text, string key, string iv)
        {
            if (String.IsNullOrEmpty(text))
                return String.Empty;

            RC2CryptoServiceProvider rc2CSP = new RC2CryptoServiceProvider();
            rc2CSP.EffectiveKeySize = 128;

            byte[] fromEncrypt;
            byte[] encrypted;

            ICryptoTransform decryptor = null;

            decryptor = rc2CSP.CreateDecryptor(Encoding.UTF8.GetBytes(key), Encoding.UTF8.GetBytes(iv));

            encrypted = Convert.FromBase64String(text);

            MemoryStream msDecrypt = new MemoryStream(encrypted);
            CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);

            fromEncrypt = new byte[encrypted.Length];

            csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);

            csDecrypt.Close();
            csDecrypt.Clear();
            msDecrypt.Close();
            rc2CSP.Clear();

            return Encoding.UTF8.GetString(fromEncrypt).TrimEnd('\0');
        }

        #region Properties
        internal string Text
        {
            get { return _text; }
        }
        internal string PathInTemplate
        {
            get { return _pathInTemplate; }
            set { _pathInTemplate = value; }
        }
        internal bool Debug
        {
            get { return _debug; }
        }
        internal bool IsAdmin
        {
            get { return _isAdmin; }
        }
        internal string RunAt
        {
            get { return _runAt; }
        }
        /*是否是站群*/
        internal bool IsMultiSite
        {
            get
            {
                return _dynamicTemplate != null && _dynamicTemplate.ContainsKey("DynamicSiteID");
            }
        }

        private Manager Manager
        {
            get
            {
                if (_manager == null)
                    return (Manager)HttpContext.Current.Application["Manager"];

                return _manager;
            }
        }
        private DataRow[] Words
        {
            get
            {
                if (_words != null)
                    return _words;

                using (AliCMS.SystemModule.Template.IDictionary bll = (AliCMS.SystemModule.Template.IDictionary)Manager.CreateObject("Template.Dictionary", 0, null, false))
                {
                    Dictionary<string, object> condition = new Dictionary<string, object>();
                    condition[Alias.Template.Dictionary.TemplatePath] = _templatePath;
                    condition[Alias.Template.Dictionary.Language] = _targetLang;

                    DataTable table = bll.List(-1, -1, condition, null);
                    table.Columns.Add("Width", typeof(int)).Expression = "LEN(" + Alias.Template.Dictionary.From + ")";
                    _words = table.Select("", "Width DESC");
                }

                return _words;
            }
        }
        #endregion

        #region Fields
        private string _text;
        private string _baseClass;
        private string _runAt;
        private string _templateName;
        private string _className;
        private string _object;
        private string _templatePath;
        Dictionary<string, object> _template;
        private DataRow _mainModule;
        private DataRow _module;
        private DataTable _moduleTable;
        private DataTable _templateModuleTable;
        private List<Tag> _tags;
        private List<string> _assemblies;
        private StringBuilder _tagCode;
        private Dictionary<string, string> _usedVars;
        private List<string> _usedChannel;
        private List<string> _usedFunctions;
        private Dictionary<string, DataTable> _moduleToObjectTable;
        private DataRow[] _words;
        private string _targetLang;
        private AliCMS.SystemModule.Template.IPage _page;
        private string _lang;
        private string _pathInTemplate;
        private string _pathInChannel;
        private Manager _manager = null;
        private bool _isControl;
        private bool _debug;
        private bool _vedit;
        private string _veCachePrefix;
        private string _veFolder;
        private string _veTemplatePath;
        private string _veChannelPath;
        private string _veSource;
        private string _veTarget;
        private bool _isAdmin;
        private Dictionary<string, string> _dynamicTemplate;
        #endregion
    }
}
